/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package uk.co.alt236.btlescan.slice;

import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.ListContainer;
import ohos.agp.components.RoundProgressBar;
import ohos.agp.components.Text;
import ohos.bluetooth.ProfileBase;
import ohos.bluetooth.ble.BlePeripheralCallback;
import ohos.bluetooth.ble.BlePeripheralDevice;
import ohos.bluetooth.ble.BleScanResult;
import ohos.bluetooth.ble.GattCharacteristic;
import ohos.bluetooth.ble.GattDescriptor;
import ohos.bluetooth.ble.GattService;
import uk.co.alt236.bluetoothlelib.device.BluetoothLeDevice;
import uk.co.alt236.bluetoothlelib.resolvers.GattAttributeResolver;
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
import uk.co.alt236.btlescan.ResourceTable;
import uk.co.alt236.btlescan.adapter.ConnectItemProvider;

import java.util.Arrays;
import java.util.List;
import java.util.UUID;

/**
 * DeviceAbilitySlice
 *
 * @author ljx
 * @since 2021-04-29
 */
public class DeviceControlAbilitySlice extends AbilitySlice {
    private static final String MDISCONNECTSTR = "DISCONNECT";
    private static final String MCONNECTINGSTR = "connecting";
    private static final String MCONNECTSTR = "CONNECT";
    private static final String MUNKNOWNSTR = "unknown";
    private static final String MUUIDSTR = "UUID：";
    private static final String MDESCSTR = "Desc：";
    private static final String ASSTRING = "As String：";
    private static final String ASARRAY = "As Array：";
    private static final int INCREASEROTATE = 20;
    private static final int MAXROTATE = 360;
    private static final int DELAYTIME = 100;
    private boolean isFirst = true;
    private BlePeripheralDevice peripheraDevice;
    private Text mState;
    private RoundProgressBar mProgressBar;
    private Button mConnect;
    private int rotate = 0;
    private boolean isRotation = true;
    private Text mUuid;
    private Text mDesc;
    private Text mStr;
    private Text mArr;
    private ListContainer listContainer;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_device_control);
        initView();
        BluetoothLeDevice device = intent.getSequenceableParam("device");
        Text titlebar = (Text) findComponentById(ResourceTable.Id_tv_title);
        titlebar.setText(device.getName());
        Text address = (Text) findComponentById(ResourceTable.Id_address);
        address.setText(device.getAddress());
        BleScanResult bleDevice = device.getDevice();
        peripheraDevice = bleDevice.getPeripheralDevice();

        // 与外围设备建立连接，允许自动回连，连接会触发connectionStateChangedEvent回调
        MyBlePeripheralCallback callback = new MyBlePeripheralCallback();
        peripheraDevice.connect(true, callback);

        // 连接后读取外围设备RSSI值，获取后触发readRemoteRssiEvent()回调
        peripheraDevice.readRemoteRssiValue();
        mState.setText(MCONNECTINGSTR);
        mConnect.setText(MDISCONNECTSTR);
        startRotate();
        mConnect.setClickedListener(v -> {
            String text = mConnect.getText();
            if (MCONNECTSTR.equals(text)) {
                startRotate();
                mState.setText(MCONNECTINGSTR);
                mConnect.setText(MDISCONNECTSTR);
                peripheraDevice.connect(true, callback);
                peripheraDevice.readRemoteRssiValue();
            } else {
                stopRotate();
                peripheraDevice.disconnect();
                mState.setText("disconnect");
                mConnect.setText(MCONNECTSTR);
            }
        });
    }

    private void initView() {
        mState = (Text) findComponentById(ResourceTable.Id_ble_state);
        mProgressBar = (RoundProgressBar) findComponentById(ResourceTable.Id_round_progress_bar);
        mConnect = (Button) findComponentById(ResourceTable.Id_disconnect);
        listContainer = (ListContainer) findComponentById(ResourceTable.Id_listcontainer);
        mUuid = (Text) findComponentById(ResourceTable.Id_uuid);
        mDesc = (Text) findComponentById(ResourceTable.Id_desc);
        mStr = (Text) findComponentById(ResourceTable.Id_as_string);
        mArr = (Text) findComponentById(ResourceTable.Id_as_array);
    }

    /**
     * 实现外围设备操作回调
     *
     * @author ljx
     * @since 2021-04-29
     */
    private class MyBlePeripheralCallback extends BlePeripheralCallback {
        @Override
        public void connectionStateChangeEvent(int connectionState) {
            super.connectionStateChangeEvent(connectionState);
            if (connectionState == ProfileBase.STATE_CONNECTED) {
                peripheraDevice.discoverServices(); // 连接成功获取外围设备的Service
                getUITaskDispatcher().asyncDispatch(() -> {
                    mState.setText("connected");
                    mConnect.setText(MDISCONNECTSTR);
                    stopRotate();
                    listContainer.setVisibility(Component.VISIBLE);
                });
            }
            if (connectionState == ProfileBase.STATE_CONNECTING) {
                // 连接中
                getUITaskDispatcher().asyncDispatch(() -> {
                    mState.setText(MCONNECTINGSTR);
                    mConnect.setText(MDISCONNECTSTR);
                    startRotate();
                    listContainer.setVisibility(Component.INVISIBLE);
                });
            }
            if (connectionState == ProfileBase.STATE_DISCONNECTED) {
                // 连接断开
                getUITaskDispatcher().asyncDispatch(() -> {
                    mState.setText("disconnected");
                    mConnect.setText(MCONNECTSTR);
                    stopRotate();
                    listContainer.setVisibility(Component.INVISIBLE);
                });
            }
        }

        @Override
        public void servicesDiscoveredEvent(int status) {
            // 获取外围设备Service的回调
            if (status == BlePeripheralDevice.OPERATION_SUCC) {
                if (isFirst) {
                    // 获取Service成功后获服务列表
                    List<GattService> services = peripheraDevice.getServices();
                    ConnectItemProvider provider = new ConnectItemProvider(services, DeviceControlAbilitySlice.this);
                    getUITaskDispatcher().asyncDispatch(new Runnable() {
                        @Override
                        public void run() {
                            isFirst = false;
                            listContainer.setItemProvider(provider);
                        }
                    });
                }
            }
        }

        @Override
        public void characteristicChangedEvent(GattCharacteristic charecteristic) {
            // 外围设备主动向中心设备发送特征值通知时触发回调
            // 根据通知的charecteristic获取特征值携带的数据
            UUID uuid = charecteristic.getUuid();
            byte[] value = charecteristic.getValue();
            String attribute = GattAttributeResolver.getAttributeName(uuid.toString(), MUNKNOWNSTR);
            getUITaskDispatcher().asyncDispatch(new Runnable() {
                @Override
                public void run() {
                    mUuid.setText(MUUIDSTR + uuid.toString());
                    mDesc.setText(MDESCSTR + attribute);
                    mStr.setText(ASSTRING + Arrays.toString(value));
                    mArr.setText(ASARRAY + ByteUtils.byteArrayToHexString(value));
                }
            });
        }

        @Override
        public void characteristicWriteEvent(GattCharacteristic charecteristic, int ret) {
            if (ret == BlePeripheralDevice.OPERATION_SUCC) {
                // 向外围设备写特征值数据成功后的操作
                UUID uuid = charecteristic.getUuid();
                byte[] value = charecteristic.getValue();
                String attribute = GattAttributeResolver.getAttributeName(uuid.toString(), MUNKNOWNSTR);
                getUITaskDispatcher().asyncDispatch(new Runnable() {
                    @Override
                    public void run() {
                        mUuid.setText(MUUIDSTR + uuid.toString());
                        mDesc.setText(MDESCSTR + attribute);
                        mStr.setText(ASSTRING + Arrays.toString(value));
                        mArr.setText(ASARRAY + ByteUtils.byteArrayToHexString(value));
                    }
                });
            }
        }

        @Override
        public void characteristicReadEvent(GattCharacteristic charecteristic, int ret) {
            if (ret == BlePeripheralDevice.OPERATION_SUCC) {
                // 向外围设备写特征值数据成功后的操作
                UUID uuid = charecteristic.getUuid();
                byte[] value = charecteristic.getValue();
                String attribute = GattAttributeResolver.getAttributeName(uuid.toString(), MUNKNOWNSTR);
                getUITaskDispatcher().asyncDispatch(new Runnable() {
                    @Override
                    public void run() {
                        mUuid.setText(MUUIDSTR + uuid.toString());
                        mDesc.setText(MDESCSTR + attribute);
                        mStr.setText(ASSTRING + Arrays.toString(value));
                        mArr.setText(ASARRAY + ByteUtils.byteArrayToHexString(value));
                    }
                });
            }
        }

        @Override
        public void descriptorReadEvent(GattDescriptor descriptor, int ret) {
            // 向外围设备读描述值数据成功后的操作
        }

        @Override
        public void descriptorWriteEvent(GattDescriptor descriptor, int ret) {
            // 向外围设备写描述值数据成功后的操作
        }

        @Override
        public void readRemoteRssiEvent(int rssi, int ret) {
            // 读取外围设备RSSI值成功后的操作，对端RSSI值为rssi
        }
    }

    private void startRotate() {
        isRotation = true;
        mProgressBar.setVisibility(Component.VISIBLE);
        getUITaskDispatcher().delayDispatch(() -> {
            rotate = rotate + INCREASEROTATE;
            if (rotate == MAXROTATE) {
                rotate = 0;
            }
            if (isRotation && mProgressBar != null && mProgressBar.getVisibility() == Component.VISIBLE) {
                mProgressBar.setRotation(rotate);
                startRotate();
            }
        }, DELAYTIME);
    }

    private void stopRotate() {
        isRotation = false;
        mProgressBar.setVisibility(Component.INVISIBLE);
    }

    @Override
    protected void onStop() {
        super.onStop();
        stopRotate();
        peripheraDevice.disconnect();
    }

    @Override
    public void onActive() {
        super.onActive();
    }

    @Override
    public void onForeground(Intent intent) {
        super.onForeground(intent);
    }
}